grammar Cymbol;

compilationUnit // [编译单元]
    :   (classDefinition | methodDeclaration | varDeclaration)+
    ;

// START: class
classDefinition // [类定义]
    :   'class' ID superClass? '{' classMember+ '}' ';'
    ;
superClass
	:	':' 'public' ID
	;
	
classMember
    :	type ID ('=' expression)? ';'  # classFieldDeclaration     // [字段定义] ，注意这里的字段定义不能和变量定义合并，因为在编译单元里还需要使用到
    |	methodDeclaration              # classMethodDeclaration    // [方法定义]
    |	'public' ':'                   # publicModifier // throw away; just making input valid C++
    ;
// END: class

// START: method
methodDeclaration
    :   type ID '(' formalParameters? ')' block
    ;
// END: method

formalParameters    // [参数列表]
    :   type ID (',' type ID)*
    ;

type:   'float'
    |   'int'
    |	'void'
    |   ID  // class 类型名
    ;

// START: block
block   // [块语句]
    :   '{' statement* '}'
    ;
// END: block

// START: var
varDeclaration // [变量定义]
    :   type ID ('=' expression)? ';'
    ;
// END: var

statement
    :   block                                   # blockStatement
    |	varDeclaration                          # varDeclarationStatement 
    |   RETURN expression? ';'                  # returnStatement   // [返回语句]
    |   postfixExpression ';'                   # callStatement // handles function calls like f(i);
    |   postfixExpression '=' expression ';'    # assignmentExpression  // [赋值语句]
    |   ';'                                     # emptyStatement// empty statement
    ;

expressionList
    :   expression (',' expression)*
    ;

expression
    :   addExpression
    ;

addExpression
	:	postfixExpression ('+' postfixExpression)*
	;

postfixExpression
    :   primary option*
    ;

option
	:	'.' ID '(' expressionList? ')'  # methodCall     // [方法调用]
	|	'.' ID						    # memberAccess   // [成员访问]
	|	'(' expressionList? ')'         # functionCall   // [函数调用]
	;
	
primary
    :   THIS
    |	SUPER
    |	ID
    |   INT
    |   '(' expression ')'
    ;

// LEXER RULES


THIS : 'this';
SUPER : 'super';
RETURN : 'return';

ID  :   LETTER (LETTER | '0'..'9')*
    ;

fragment
LETTER  :   ('a'..'z' | 'A'..'Z')
    ;

INT :   '0'..'9'+
    ;

WS  :   (' '|'\r'|'\t'|'\n') -> skip
    ;

SL_COMMENT
    :   '//' ~('\r'|'\n')* '\r'? '\n' -> skip
    ;
